package com.example.core.common;

import com.example.core.annotation.CacheLock;
import com.example.core.annotation.CacheParam;
import com.example.core.common.CacheKeyGenerator;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * @Author: 胡成
 * @Version: 0.0.1V
 * @Date: 2019/2/2
 * @Description: 类描述
 **/
@Component
public class LockKeyGenerator implements CacheKeyGenerator {

    @Override
    public String getLockKey(ProceedingJoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        CacheLock lock = method.getAnnotation(CacheLock.class);
        final Object[] args = point.getArgs();
        final Parameter[] paramters = method.getParameters();
        StringBuffer buffer = new StringBuffer();
        //默认解析方法里面带的CacheParam 注解的属性,如果没有尝试着解析实体对象中的
        for (int i = 0; i < paramters.length; i++) {
            final CacheParam annotation = paramters[i].getAnnotation(CacheParam.class);
            if (annotation == null) {
                continue;
            }

            buffer.append(lock.delimiter()).append(args[i]);
        }
        if (StringUtils.isEmpty(buffer.toString())) {
            final Annotation[][] annotations = method.getParameterAnnotations();
            for (int i = 0; i < annotations.length; i++) {
                final Object object = args[i];
                final Field[] fields = object.getClass().getDeclaredFields();
                for (Field field : fields) {
                    final CacheParam annotation = field.getAnnotation(CacheParam.class);
                    if (annotation == null) {
                        continue;
                    }
                    field.setAccessible(true);
                    buffer.append(lock.delimiter()).append(ReflectionUtils.getField(field, object));
                }

            }
        }
        return lock.prefix() + buffer.toString();
    }
}
